/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Registry Access Class
 *		This class provides an easy interface to reading and saving 
 * items in the registry, and other various registry functions.
 *--------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
 * System Imports
 *--------------------------------------------------------------------------*/
using System;
using System.Text;
using Microsoft.Win32;
using System.Collections.Specialized;

namespace Adaptive.Foundation.SysTools
{
    /// <summary>
    /// Provides an easy interface to reading and saving items in the registry, and 
    /// access to other various registry functions.
    /// </summary>
    /// <remarks>
    /// All of the methods on this class are static/shared methods.  A type instance
    /// of this class is not required.
    /// </remarks>
    public static class RegistryOps
    {
        /*----------------------------------------------------------------------------
		 * Public Static / Shared Methods / Functions
		 *--------------------------------------------------------------------------*/
        #region Public Static / Shared Methods / Functions
        /// <summary>
        /// Returns a <see cref="RegistryKey"/> object under the HKEY_LOCAL_MACHINE segment of the registry.
        /// </summary>
        /// <param name="keyName">The registry path, not including \HKEY_LOCAL_MACHINE, of the key to be opened.</param>
        /// <returns>
        /// Returns a <see cref="RegistryKey"/> object representing the specified key, if the key 
        /// is present and available for opening.  Otherwise, returns <b>null</b>.
        /// </returns>
        public static RegistryKey OpenLocalMachineRegistryKey(string keyName)
        {
            RegistryKey returnValue = null;		//Return value.
            try
            {
                returnValue = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(keyName, true);
            }
            catch (ArgumentNullException)
            {
                returnValue = null;
            }

            return returnValue;

        }
        /// <summary>
        /// Reads a setting from the registry at a specified location.
        /// </summary>
        /// <param name="appName">The Application/Section Name.</param>
        /// <param name="section">The section name / registry key name.</param>
        /// <param name="itemName">The registry value to be read.</param>
        /// <param name="defaultValue"></param>
        /// <remarks>
        /// This method works similarly to the old Visual Basic <b>GetSetting</b> method, with the 
        /// exception that all keys to be read are under the HKEY_CURRENT_USER\Software branch of the
        /// registry.  This method works in conjunction with the <b>Microsoft.Win32.Registry.SaveSetting</b> method.
        /// </remarks>
        /// <returns>
        /// if ( the specified key is present and no exceptions occur while reading the key, the value
        /// of the registry setting is returned.  Otherwise, the supplied default value is returned.
        /// </returns>
        public static object ReadSetting(string appName, string section,
            string itemName, object defaultValue)
        {
            //Reads an application setting from a specific location in the registry.
            //Parameters:    sAppName - The name of the application.
            //               sSection - The registry section to look under.
            //               sItemName - The name of the item to look up the value for.
            //               objDefault - The default value for this item.

            //This method looks under the following location for app settings:
            //HKEY_CURRENT_USER\Software\
            RegistryKey software = null;		 //The HKEY_CURRENT_USER\Software\ Registry location.;
            RegistryKey key = null;			//The actual item being read.;
            object returnValue = null;			//Return value.

            //Attempt to access the Software registry key.
            try
            {
                software = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", false);
            }
            catch (ArgumentNullException)
            {
                software = null;
            }

            //if ( successful, attempt to access the specified registry sub key.
            if (software != null)
            {
                key = OpenKey(software, appName, section, false);
                if (key != null)
                {
                    //Read the value.
                    returnValue = key.GetValue(itemName, defaultValue);
                    key.Close();

                }
                else

                    //if ( the setting does not exist, return the default value.
                    returnValue = defaultValue;

                software.Close();
            }
            else
                returnValue = defaultValue;


            software = null;
            key = null;
            return returnValue;

        }
        //A series of data-type specific SaveSetting() methods which all call the private
        //m_SaveSetting() method.
        /// <summary>
        /// Saves string value to a specified location in the registry.
        /// </summary>
        /// <param name="appName">The Application / section name.</param>
        /// <param name="section">The section / registry key name.</param>
        /// <param name="itemName">The registry value / item name.</param>
        /// <param name="value">The value to be stored in the registry.</param>
        /// <remarks>
        /// This method works similarly to the old Visual Basic SaveSetting method, except
        /// that the values are all saved under the HKEY_CURRENT_USER\Software branch of the 
        /// registry.  Several overloaded methods are provided for strong-typing.
        /// </remarks>
        public static void SaveSetting(string appName, string section, string itemName, string value)
        {
            SaveSetting(appName, section, itemName, value);
        }
        /// <summary>
        /// Saves an integer value to a specified location in the registry.
        /// </summary>
        /// <param name="appName">The Application / section name.</param>
        /// <param name="section">The section / registry key name.</param>
        /// <param name="itemName">The registry value / item name.</param>
        /// <param name="value">The value to be stored in the registry.</param>
        /// <remarks>
        /// This method works similarly to the old Visual Basic SaveSetting method, except
        /// that the values are all saved under the HKEY_CURRENT_USER\Software branch of the 
        /// registry.  Several overloaded methods are provided for strong-typing.
        /// </remarks>
        public static void SaveSetting(string appName, string section, string itemName, int value)
        {
            SaveSetting(appName, section, itemName, value);
        }
        /// <summary>
        /// Saves a date value to a specified location in the registry.
        /// </summary>
        /// <param name="appName">The Application / section name.</param>
        /// <param name="section">The section / registry key name.</param>
        /// <param name="itemName">The registry value / item name.</param>
        /// <param name="value">The value to be stored in the registry.</param>
        /// <remarks>
        /// This method works similarly to the old Visual Basic SaveSetting method, except
        /// that the values are all saved under the HKEY_CURRENT_USER\Software branch of the 
        /// registry.  Several overloaded methods are provided for strong-typing.
        /// </remarks>
        public static void SaveSetting(string appName, string section, string itemName, DateTime value)
        {
            SaveSetting(appName, section, itemName, value);
        }
        /// <summary>
        /// Saves a long value to a specified location in the registry.
        /// </summary>
        /// <param name="appName">The Application / section name.</param>
        /// <param name="section">The section / registry key name.</param>
        /// <param name="itemName">The registry value / item name.</param>
        /// <param name="value">The value to be stored in the registry.</param>
        /// <remarks>
        /// This method works similarly to the old Visual Basic SaveSetting method, except
        /// that the values are all saved under the HKEY_CURRENT_USER\Software branch of the 
        /// registry.  Several overloaded methods are provided for strong-typing.
        /// </remarks>
        public static void SaveSetting(string appName, string section, string itemName, long value)
        {
            SaveSetting(appName, section, itemName, value);
        }
        /// <summary>
        /// Saves a single/float value to a specified location in the registry.
        /// </summary>
        /// <param name="appName">The Application / section name.</param>
        /// <param name="section">The section / registry key name.</param>
        /// <param name="itemName">The registry value / item name.</param>
        /// <param name="value">The value to be stored in the registry.</param>
        /// <remarks>
        /// This method works similarly to the old Visual Basic SaveSetting method, except
        /// that the values are all saved under the HKEY_CURRENT_USER\Software branch of the 
        /// registry.  Several overloaded methods are provided for strong-typing.
        /// </remarks>
        public static void SaveSetting(string appName, string section, string itemName, float value)
        {
            SaveSetting(appName, section, itemName, value);
        }
        /// <summary>
        /// Saves a double value to a specified location in the registry.
        /// </summary>
        /// <param name="appName">The Application / section name.</param>
        /// <param name="section">The section / registry key name.</param>
        /// <param name="itemName">The registry value / item name.</param>
        /// <param name="value">The value to be stored in the registry.</param>
        /// <remarks>
        /// This method works similarly to the old Visual Basic SaveSetting method, except
        /// that the values are all saved under the HKEY_CURRENT_USER\Software branch of the 
        /// registry.  Several overloaded methods are provided for strong-typing.
        /// </remarks>
        public static void SaveSetting(string appName, string section, string itemName, double value)
        {
            SaveSetting(appName, section, itemName, value);
        }
        /// <summary>
        /// Returns the application associated with the specified extension.
        /// </summary>
        /// <param name="extension">The file extension to find the associated application for.</param>
        /// <returns>Returns the application start string for the specified extension.</returns>
        /// <remarks>
        /// This method looks through the registered extension classes section of the
        /// registry for the application associated with that file extension.  This is the value that
        /// is set with Windows Explorer//s <b>Open With...</b> command.  The returned value is not
        /// neccessarily just an executable path and name.  Some strings contain various flags and
        /// substitution values.  if ( the value <b>%1</b> is present in the returned string, it is
        /// intended that the <b>%1</b> in that string be replaced with the path and name of the 
        /// file that is to be opened.
        /// </remarks>
        public static string GetFileExtensionAppName(string extension)
        {
            //Returns the application responsible for opening files with the specified extension.
            //Paramater:     sExtension - The extension to look up.
            //return value:  string  - The application location\name for this extension.

            //This function looks for the application by attempting to find a registry entry
            //in HKEY_CLASSES_ROOT\.<Extension>.

            RegistryKey shellKey = null;
            string documentName = string.Empty;
            string appName = string.Empty;

            //get { the document object name for this extension.
            documentName = GetFileExtDocumentObjectName(extension);

            //Attempt to get the value in:
            //  HKEY_CLASSES_ROOT\<Document object Name>\shell\open\command"
            try
            {
                shellKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(
                    documentName + "\\shell\\open\\command", false);
            }
            catch (ArgumentNullException)
            {
                shellKey = null;
            }

            //if ( Successful, get the application name.
            if (shellKey != null)
            {
                appName = (string)shellKey.GetValue(string.Empty);
                shellKey.Close();

            }
            shellKey = null;
            documentName = null;

            return appName;

        }
        /// <summary>
        /// Gets the file type for the specified extension.
        /// </summary>
        /// <param name="extension">
        /// The extension to search for.
        /// </param>
        /// <returns>
        /// The Windows associated file type name.
        /// </returns>
        public static string GetFileExtensionTypeName(string extension)
        {
            //Returns the application responsible for opening files with the specified extension.
            //Paramater:     sExtension - The extension to look up.
            //return value:  string  - The application location\name for this extension.

            //This function looks for the application by attempting to find a registry entry
            //in HKEY_CLASSES_ROOT\.<Extension>.

            RegistryKey shellKey = null;
            string documentName = string.Empty;
            string appName = string.Empty;

            //get { the document object name for this extension.
            documentName = GetFileExtDocumentObjectName(extension);

            //Attempt to get the value in:
            //  HKEY_CLASSES_ROOT\<Document object Name>\shell\open\command"
            try
            {
                shellKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(documentName, false);
            }
            catch (ArgumentNullException)
            {
                shellKey = null;
            }

            //if ( Successful, get the application name.
            if (shellKey != null)
            {
                appName = (string)shellKey.GetValue(string.Empty);
                shellKey.Close();

            }
            shellKey = null;
            documentName = null;

            return appName;

        }
        /// <summary>
        /// Returns the MIME content description for the file type with the specified extension.
        /// </summary>
        /// <param name="sExtension">The file extension to find a MIME description for.</param>
        /// <returns>Returns the associated MIME file type description for the file type that 
        /// has the specified file extension.</returns>
        /// <remarks>
        /// This method looks through the registered extension classes section of the registry for
        /// the specified file extension, and if present, then searches for the file type and 
        /// MIME-64 content description association.  if ( such a key is present, the value of that
        /// key is returned.  This is used to create header data for MIME-64 file attachment text
        /// in e-mails.
        /// </remarks>
        public static string GetFileContentDescription(string sExtension)
        {

            //Returns the content description, if present, for a supplied file extension.
            //Paramater:     sExtension - The extension to look up.
            //return value:  string  - The application location\name for this extension.

            //This function looks for the application by attempting to find a registry entry
            //in HKEY_CLASSES_ROOT\.<Extension>.

            //This function retrieves the registry object name that is associated with
            //a file extension.
            //Parameter:     sExtension - The file extension to look for.
            //return value:  string  - The content type description.

            RegistryKey objClassRoot;

            string sDesc = string.Empty;

            //Attempt to access the Root Classes\Extension registry key.
            try
            {
                objClassRoot = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey("." +
                    sExtension, false);
            }
            catch (ArgumentNullException)
            {
                objClassRoot = null;
            }

            //if ( successful, get the default value of the key.
            if (!(objClassRoot == null))
            {

                sDesc = (string)(objClassRoot.GetValue("Content Type"));
                objClassRoot.Close();

            }
            objClassRoot = null;
            return sDesc;
        }
        /// <summary>
        /// Returns the value of the specified registry key.
        /// </summary>
        /// <param name="sKey">The path and name of the registry key to be accessed.</param>
        /// <param name="itemName">The name of the registry value to be read.</param>
        /// <returns>if ( the specified registry key and value are present, and no
        /// exception occurs during read, the method returns the value stored in the 
        /// registry.  Otherwise, it returns a blank string.
        /// </returns>
        /// <remarks>
        /// This method is provided as a short-cut method for reading registry items
        /// under the HKEY_LOCAL_MACHINE\SOFTWARE branch of the registry.
        /// </remarks>
        public static string GetValueForSoftwareKey(string sKey, string itemName)
        {

            RegistryKey objKey;
            string sReturn = string.Empty;

            try
            {
                objKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
                    "SOFTWARE\\" + sKey);
            }
            catch (ArgumentNullException)
            {
                objKey = null;
            }
            if (!(objKey == null))
            {
                sReturn = (string)objKey.GetValue(itemName, string.Empty);
                objKey.Close();
            }

            objKey = null;
            return sReturn;

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="keyName"></param>
        /// <param name="itemName"></param>
        /// <returns></returns>
        public static string GetValueForLocalMachineKey(string keyName, string itemName)
        {
            StringBuilder builder = null;
            RegistryKey key = null;			//Key value to read.
            object dataItem = null;			//Raw (boxed) data value.
            string returnValue = string.Empty;	//Return value.
            string[] info = null;
            int count = 0;						//Iteration counter.
            int length = 0;

            try
            {
                key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(keyName);
            }
            catch (ArgumentNullException)
            {
                key = null;
            }

            if (key != null)
            {

                dataItem = key.GetValue(itemName, string.Empty);
                if (dataItem.GetType() == typeof(string))
                    returnValue = (string)(dataItem);
                else if (dataItem.GetType() == typeof(Array))
                {
                    info = (string[])dataItem;
                    builder = new StringBuilder();
                    length = info.Length;
                    for (count = 0; count < length; count++)
                        builder.Append(info[count] + "\r\n");
                    Array.Clear(info, 0, length);
                    info = null;
                    returnValue = builder.ToString();
                    builder = null;
                }
                else
                    returnValue = (string)dataItem;

                key.Close();
            }
            info = null;
            key = null;
            return returnValue;
        }
        /// <summary>
        /// Returns the list of ODBC DSNs on the local machine.
        /// </summary>
        /// <returns>Returns a <see cref="StringCollection"/>containing the DSN names
        /// stored in the registry.</returns>
        /// <remarks>
        /// This method reads the values for ODBC DSN entries that are stored in the 
        /// registry.  This does not neccessarily mean that the DSN names returned 
        /// are currently valid, or represent the servers on the network.
        /// </remarks>
        public static StringCollection GetDataSourceList()
        {

            StringCollection returnValue = null;
            RegistryKey objKey;
            int iCount;
            int iLen;
            string[] sNames;
            string sDesc;

            returnValue = new StringCollection();

            try
            {
                objKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
                    @"SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources");
            }
            catch (ArgumentNullException)
            {
                objKey = null;
            }
            if (!(objKey == null))
            {
                sNames = objKey.GetValueNames();
                iLen = objKey.ValueCount - 1;
                for (iCount = 0; iCount <= iLen; iCount++)
                {
                    sDesc = (string)(objKey.GetValue(sNames[iCount], string.Empty));
                    sDesc = sDesc.ToLower();

                    if (sDesc.IndexOf("sql server") > -1)
                    {
                        returnValue.Add(sNames[iCount]);
                    }
                } //
                sNames = null;
                objKey.Close();
            }

            objKey = null;
            sNames = null;
            return returnValue;

        }
        public static void SaveSetting(string appName, string section, string itemName, object objValue)
        {
            //Saves specified settings in the registry.
            //Parameters:    appName - The application name to use as a key.
            //               section - The section name to use as a sub-key.
            //               itemName - The name of the registry value entry.
            //               objValue - The data to be saved as the registry value.

            RegistryKey objSoftware;
            RegistryKey objRegKey;

            //This stores data under HKEY_CURRENT_USER\Software\
            objSoftware = OpenMainKey();
            if (objSoftware != null)
            {
                //Attempt to open/create the Application-level\Section registry key.
                objRegKey = OpenKey(objSoftware, appName, section, true);
                if (objRegKey != null)
                {
                    //Save the value.
                    try
                    {
                        objRegKey.SetValue(itemName, objValue);
                        objRegKey.Close();
                    }
                    catch (ArgumentNullException)
                    {
                        objRegKey = null;
                    }

                }
                objSoftware.Close();
            }

            objSoftware = null;
            objRegKey = null;

        }
        public static RegistryKey OpenKey(RegistryKey objSoft, string appName, string section, bool bWrite)
        {
            //Opens the application registry key under HKEY_CURRENT_USER\Software
            //Parameters:    objSoft - An open registry key representing HKEY_CURRENT_USER\Software
            //               appName - The name of the application-level key to open.
            //               section - The name of the section sub-key to open.
            //               bWrite - Flag to indicate open for writing or not.
            //return value:  RegistryKey - return the opened key if successful, null on failure.

            RegistryKey objReturn;

            if (!(objSoft == null))
            {

                //try { to open the key.  if ( it does not exist, create it.
                try
                {
                    objReturn = objSoft.OpenSubKey(appName + "\\" + section, bWrite);
                    if (objReturn == null)
                    {
                        objReturn = objSoft.CreateSubKey(appName + "\\" + section);
                    }
                }
                catch (ArgumentNullException)
                {
                    objReturn = null;
                }

            }
            else
            {
                objReturn = null;
            }
            return objReturn;

        }
        public static RegistryKey OpenMainKey()
        {
            //Opens the "main" key - HKEY_CURRENT_USER\Software
            //return value:  RegistryKey - An object representing the Main key.

            RegistryKey objSoftware;

            try
            {
                objSoftware = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);
            }
            catch (ArgumentNullException)
            {
                objSoftware = null;
            }

            return objSoftware;

        }
        /// <summary>
        /// Gets the registry's document object name for the specified file extension.
        /// </summary>
        /// <param name="extension">
        /// The file extension to check for.
        /// </param>
        /// <returns>
        /// A string value containing the document name.
        /// </returns>
        public static string GetFileExtDocumentObjectName(string extension)
        {
            //This function retrieves the registry object name that is associated with
            //a file extension.
            //Parameter:     sExtension - The file extension to look for.
            //return value:  string  - The object name of associated with the extension.

            RegistryKey classRootKey = null;
            string name = string.Empty;

            //Attempt to access the Root Classes\Extension registry key.
            try
            {
                classRootKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey("." + extension, false);
            }
            catch (ArgumentNullException)
            {
                classRootKey = null;
            }

            //if ( successful, get the default value of the key.
            if (!(classRootKey == null))
            {

                name = (string)(classRootKey.GetValue(string.Empty));
                classRootKey.Close();

            }
            classRootKey = null;
            return name;

        }
        public static string ReadDefaultValue(RegistryKey root, string keyName)
        {
            string returnValue = string.Empty;		//Return value.
            Microsoft.Win32.RegistryKey key = null;	//Key to be opened.

            try
            {
                key = root.OpenSubKey(keyName, false);
                returnValue = (string)key.GetValue(string.Empty, string.Empty);
                key.Close();
            }
            catch (ArgumentNullException)
            {
            }
            key = null;
            return returnValue;
        }
        #endregion

    }
}
